package de.Hijack.Giuliani;

import org.redpin.android.core.Measurement;
import org.redpin.android.net.InternetConnectionManager;
import org.redpin.android.net.wifi.WifiSniffer;

import android.app.AlertDialog;
import android.app.ProgressDialog;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.DialogInterface;
import android.content.DialogInterface.OnClickListener;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.ServiceConnection;
import android.location.Criteria;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Environment;
import android.os.IBinder;
import android.os.Vibrator;
import android.util.Log;
import android.view.KeyEvent;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;

import android.widget.LinearLayout;
import com.google.android.maps.GeoPoint;
import com.google.android.maps.MapActivity;
import com.google.android.maps.MapController;
import com.google.android.maps.MapView;
import com.google.android.maps.MyLocationOverlay;

public class MainMapActivity extends MapActivity {

    /**
     * android Log TAG
     */
    private static final String TAG = "MapActivity";
    private MapView mapView;
    private MapController mapController;
    private Location position = new Location(LocationManager.GPS_PROVIDER);
    public Measurement lastKnownMeasurement;
    private DBAdapter adapter;
    // overlays
    private WayPointOverlay points;
    public MapOverlay maps;
    private MyLocationOverlay myLocationOverlay;
    private LinearLayout floorButtons;
    WifiSniffer mWifiService;
    public int mode = MODE_GPS;
    public static final int MODE_GPS = 0;
    public static final int MODE_REDPIN = 1;

    
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        initMapView();
        initDB();
        initGUI();
        initOverlay();
        initRedpin();
    }

    private void initRedpin() {
        startWifiSniffer();
    }

    private void initGUI() {

        floorButtons = (LinearLayout) findViewById(R.id.buttons);
        floorButtons.setVisibility(View.GONE);

        ((Button) findViewById(R.id.save)).setOnClickListener(new View.OnClickListener() {

            public void onClick(View arg0) {
                savePosition("N/A");
            }
        });
        ((Button) findViewById(R.id.list)).setOnClickListener(new View.OnClickListener() {

            public void onClick(View arg0) {
                showList();
            }
        });
        ((Button) findViewById(R.id.save)).setOnClickListener(new View.OnClickListener() {

            public void onClick(View arg0) {
                savePosition("N/A");
            }
        });
        ((Button) findViewById(R.id.mode)).setOnClickListener(new View.OnClickListener() {

            public void onClick(View arg0) {
                if (mode == MODE_GPS) {
                    mode = MODE_REDPIN;
                    update();
                    floorButtons.setVisibility(View.VISIBLE);
                } else {
                    mode = MODE_GPS;
                    update();
                    floorButtons.setVisibility(View.GONE);
                }
            }
        });
    }

    private void initDB() {
        try {
            adapter.close();
        } catch (Exception e) {
            Log.v(TAG, "database not open");
        }
        adapter = new DBAdapter(this);
        adapter.open();
    }

    private void initMapView() {

        mapView = (MapView) findViewById(R.id.map_view);
        mapController = mapView.getController();

        final int maxZoomlevel = mapView.getMaxZoomLevel();
        mapController.setZoom(maxZoomlevel - 3); // zoom
        mapView.setBuiltInZoomControls(true);
        //mapView.setStreetView(true); // Strassenansicht
        mapView.setSatellite(true); // Satellitenansicht

    }

    /**
     * used to invalidate the mapView
     */
    public void update() {
        mapController.scrollBy(0, 0);
    }

    private void initLocation() {
        LocationManager locationManager =
                (LocationManager) getSystemService(Context.LOCATION_SERVICE);

        String mlocProvider;
        Criteria hdCrit = new Criteria();

        hdCrit.setAccuracy(Criteria.ACCURACY_COARSE);

        mlocProvider = locationManager.getBestProvider(hdCrit, true);

        locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 3000, 1000, new LocationListener() {

            public void onLocationChanged(Location neuePosition) {
                position = neuePosition;
            }

            public void onStatusChanged(String arg0, int arg1, Bundle arg2) {
            }

            public void onProviderEnabled(String arg0) {
            }

            public void onProviderDisabled(String arg0) {
            }
        });

        if (locationManager.getLastKnownLocation(mlocProvider) != null) {
            position = locationManager.getLastKnownLocation(mlocProvider);
        } else {
            position.setLatitude(48.99872);
            position.setLongitude(12.096964);
        }
    }

    private void initOverlay() {
        initLocation();
        mapController.animateTo(new GeoPoint(
                (int) (position.getLatitude() * 1E6),
                (int) (position.getLongitude() * 1E6)));

        maps = new MapOverlay(this, floorButtons);
        mapView.getOverlays().add(maps);

        points = new WayPointOverlay(this, adapter);
        points.addPoints(adapter.getPoints());
        mapView.getOverlays().add(points);

    }

    @Override
    protected boolean isRouteDisplayed() {
        // TODO Auto-generated method stub
        return false;
    }

    @Override
    public boolean onCreateOptionsMenu(Menu mapMenu) {
        super.onCreateOptionsMenu(mapMenu);
        MenuInflater inflater = getMenuInflater();
        inflater.inflate(R.menu.map_menu, mapMenu);
        return true;
    }

    /**
     * saves the current position with a name
     * @param name the name of the current position
     */
    void savePosition(String name) {
        if (position != null) {
            try {
                ((Vibrator) getSystemService(Context.VIBRATOR_SERVICE)).vibrate(50);
            } catch (Exception ex) {
                Log.e(TAG, "no vibrator installed!");
            }
            WayPoint p = new WayPoint(
                    (int) (position.getLatitude() * 1E6 + 5 - Math.random() * 10),
                    (int) (position.getLongitude() * 1E6 + 5 - Math.random() * 10));
            if (mode == MainMapActivity.MODE_REDPIN) {
                p.measurement = lastKnownMeasurement;
            }
            p.setDescription(name);
            adapter.addPoint(p);
            points.wayPoints_graphics = adapter.getPoints();
            mapController.animateTo(p);
        } else {
            Log.e(TAG, "no position available!!");
        }
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        int id = item.getItemId();
        switch (id) {

            case R.id.savePosition:
                savePosition("N/A");
                break;
            case R.id.exportXml:
                new SaveTask(Environment.getExternalStorageDirectory()
                        + "/WayPoints").execute();
        }
        return true;
    }

    /**
     * asynctask to save the database to the sd card
     */
    class SaveTask extends AsyncTask {

        private boolean success = false;
        private String url = "";
        ProgressDialog pd;

        public SaveTask(String url) {
            super();
            this.url = url;
        }

        @Override
        protected void onPreExecute() {
            pd = ProgressDialog.show(MainMapActivity.this, "Bitte warten", "Exportiert alle Daten auf die SD-Karte", true, false);
        }

        @Override
        protected Object doInBackground(Object... arg0) {
            success = XmlHelper.saveXml(adapter.getPoints(), url);
            return null;
        }

        @Override
        protected void onPostExecute(Object arg0) {
            pd.dismiss();
            if (success) {
                new AlertDialog.Builder(MainMapActivity.this).setTitle("Erfolg").setMessage("Datenbank erfolgreich exportiert \n(/sdcard/WayPoints.xml)").show();
            } else {
                new AlertDialog.Builder(MainMapActivity.this).setTitle("Fehler").setMessage("Fehler beim exportieren zu \n/sdcard/WayPoints.xml").show();
            }
        }
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        adapter.close();
        stopWifiSniffer();
    }

    @Override
    public void onResume() {
        super.onResume();
        if (myLocationOverlay != null && position != null) {
            myLocationOverlay.onLocationChanged(position);
        }
    }

    /**
     * show the list of all points in a dialog
     */
    private void showList() {
        String[] names = new String[points.wayPoints_graphics.size()];

        for (int i = 0; i < names.length; i++) {
            names[i] = "";
            for (int j = 0; j < 20 && j < points.wayPoints_graphics.get(i).toString().length(); j++) {
                names[i] += points.wayPoints_graphics.get(i).toString().charAt(j);
            }
            names[i] += "...";
        }

        AlertDialog.Builder builder = new AlertDialog.Builder(this);
        builder.setTitle("GeoPunkte");
        builder.setItems(names, new DialogInterface.OnClickListener() {

            public void onClick(DialogInterface dialog, int item) {
                final WayPoint point = points.wayPoints_graphics.get(item);
                mapController.animateTo(point);
                AlertDialog a = new AlertDialog.Builder(MainMapActivity.this).create();
                a.setTitle("GeoPunkt:");
                a.setMessage("lat: " + point.getLatitudeE6() + "\nlong:" + point.getLongitudeE6());
                final EditText edit = new EditText(MainMapActivity.this);
                edit.setText(point.getDescription());
                a.setView(edit);
                a.setButton(AlertDialog.BUTTON_POSITIVE, "OK", new OnClickListener() {

                    public void onClick(DialogInterface arg0, int arg1) {
                        point.setDescription(edit.getText().toString());
                        adapter.apply(point);
                        points.wayPoints_graphics = adapter.getPoints();
                    }
                });
                a.setButton(AlertDialog.BUTTON_NEGATIVE, "Loeschen", new OnClickListener() {

                    public void onClick(DialogInterface arg0, int arg1) {
                        adapter.delete(point);
                        points.wayPoints_graphics = adapter.getPoints();
                    }
                });
                a.show();
            }
        }).show();
    }

    @Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {
        if (keyCode == KeyEvent.KEYCODE_SEARCH) {
            showList();
        }
        return super.onKeyDown(keyCode, event);
    }

    // -------- Redpin Android stolen code -----------
    /**
     * Starts the sniffer and registers the receiver
     */
    private void startWifiSniffer() {
        startService(new Intent(this, WifiSniffer.class));
        bindService(new Intent(this, WifiSniffer.class), mWifiConnection, Context.BIND_AUTO_CREATE);
        registerReceiver(wifiReceiver, new IntentFilter(WifiSniffer.WIFI_ACTION));
        Log.i(TAG, "Started WifiSniffer");
    }

    /**
     * Stops the sniffer and unregisters the receiver
     */
    private void stopWifiSniffer() {
        if (mWifiService != null) {
            mWifiService.stopMeasuring();
        }
        unbindService(mWifiConnection);
        unregisterReceiver(wifiReceiver);
        Log.i(TAG, "Stopped WifiSniffer");
    }
    /**
     * {@link InternetConnectionManager} {@link ServiceConnection} to check
     * current online state
     */
    private ServiceConnection mICMConnection = new ServiceConnection() {

        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            InternetConnectionManager mManager = ((InternetConnectionManager.LocalBinder) service).getService();
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
        }
    };
    private boolean firstMeasurement = false;
    /**
     * Receives notifications about new available measurements
     */
    private BroadcastReceiver wifiReceiver = new BroadcastReceiver() {

        @Override
        public void onReceive(Context context, Intent intent) {

            lastKnownMeasurement = mWifiService.retrieveLastMeasurement();

            Log.d("Measurement", lastKnownMeasurement.toString());

            /*
            if (m == null)
            return;
            
            if (mLocation != null) {
            // Interval Scanning
            Fingerprint fp = new Fingerprint(mLocation, m);
            FingerprintRemoteHome.setFingerprint(fp,
            new RemoteEntityHomeCallback() {
            
            @Override
            public void onResponse(Response<?> response) {
            
            if (firstMeasurement) {
            progressDialog.hide();
            mapView.addNewLocation(mLocation);
            firstMeasurement = false;
            }
            
            Log
            .i(TAG,
            "addNewLocation: setFingerprint successfull");
            }
            
            @Override
            public void onFailure(Response<?> response) {
            progressDialog.hide();
            Log.i(TAG,
            "addNewLocation: setFingerprint failed: "
            + response.getStatus() + ", "
            + response.getMessage());
            }
            });
            
            } else {
            // Localization
            LocationRemoteHome.getLocation(m,
            new RemoteEntityHomeCallback() {
            
            @Override
            public void onFailure(Response<?> response) {
            progressDialog.hide();
            
            new AlertDialog.Builder(MapViewActivity.this).setMessage(response.getMessage()).setPositiveButton(android.R.string.ok, null).create().show();
            
            }
            
            @Override
            public void onResponse(Response<?> response) {
            progressDialog.hide();
            Location l = (Location) response.getData();
            showLocation(l);
            
            }
            
            });
            mWifiService.stopMeasuring();
            }
             */

        }
    };
    /** 
     * {@link ServiceConnection} for the {@link WifiSniffer}
     */
    private ServiceConnection mWifiConnection = new ServiceConnection() {

        @Override
        public void onServiceConnected(ComponentName className, IBinder service) {
            mWifiService = ((WifiSniffer.LocalBinder) service).getService();
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
            mWifiService = null;
        }
    };
}